package com.jorado.core.utility;

import java.text.DecimalFormat;
import java.util.*;

public class NumberUtils {

    private static final String DEFAULT_FORMAT = "###,##0.###";

    private static final ThreadLocal<DecimalFormat> DEFAULT_LOCAL = new ThreadLocal<DecimalFormat>() {
        @Override
        protected DecimalFormat initialValue() {
            return new DecimalFormat(DEFAULT_FORMAT);
        }
    };

    private static final ThreadLocal<Map<String, DecimalFormat>> LOCAL = new ThreadLocal<Map<String, DecimalFormat>>();

    public static DecimalFormat getDecimalFormat(String format) {
        if (StringUtils.isEmpty(format) || DEFAULT_FORMAT.equals(format)) {
            return DEFAULT_LOCAL.get();
        }
        Map<String, DecimalFormat> formatters = LOCAL.get();
        if (formatters == null) {
            formatters = new HashMap<String, DecimalFormat>();
            LOCAL.set(formatters);
        }
        DecimalFormat formatter = formatters.get(format);
        if (formatter == null) {
            formatter = new DecimalFormat(format);
            formatters.put(format, formatter);
        }
        return formatter;
    }

    public static String format(Number value, String format) {
        return getDecimalFormat(format).format(value);
    }

    public static int fibonacci(int n) {
        if (n <= 1) {
            return n;
        } else {
            return fibonacci(n - 1) + fibonacci(n - 2);
        }
    }

    public static int factorial(int number) {
        int result = 1;
        for (int factor = 2; factor <= number; factor++) {
            result *= factor;
        }
        return result;
    }

    public static Integer[] performLottery(int numNumbers, int numbersToPick) {
        List<Integer> numbers = new ArrayList<>();
        for (int i = 0; i < numNumbers; i++) {
            numbers.add(i + 1);
        }
        Collections.shuffle(numbers);
        return numbers.subList(0, numbersToPick).toArray(new Integer[numbersToPick]);
    }

    public static void quickSort(int[] arr, int left, int right) {
        int pivotIndex = left + (right - left) / 2;
        int pivotValue = arr[pivotIndex];
        int i = left;
        int j = right;
        while (i <= j) {
            while (arr[i] < pivotValue) {
                i++;
            }
            while (arr[j] > pivotValue) {
                j--;
            }
            if (i <= j) {
                int tmp = arr[i];
                arr[i] = arr[j];
                arr[j] = tmp;
                i++;
                j--;
            }
            if (left < i) {
                quickSort(arr, left, j);
            }
            if (right > i) {
                quickSort(arr, i, right);
            }
        }
    }

    public static boolean isPrime(int number) {
        if (number < 3) {
            return true;
        }
        // check if n is a multiple of 2
        if (number % 2 == 0) {
            return false;
        }
        // if not, then just check the odds
        for (int i = 3; i * i <= number; i += 2) {
            if (number % i == 0) {
                return false;
            }
        }
        return true;
    }

    public static int gcd(int a, int b) {
        if (b == 0) {
            return a;
        }
        return gcd(b, a % b);
    }
}